/*
 *
 *  File: 'bogglemodule.cpp'
 *
 *  Author: Samip Shah <samipshah@alumni.cmu.edu>
 *  Date: Sep 24, 2011
 *
 */

#include <Python.h>
#include <boggle.h>
#include <iostream>

extern "C" {
  static PyObject* boggle_generateAndLoadBoard(PyObject* self\
      , PyObject* args);
  static PyObject* boggle_addWordToDictionary(PyObject* self\
      , PyObject* args);
  static PyObject* boggle_wordExistsInDictionary(PyObject* self\
      , PyObject* args);
  static PyObject* boggle_checkAnswers(PyObject* self\
      , PyObject* args);
}

static Boggle game;
static PyObject* FALSE;
static PyObject* TRUE;

static PyMethodDef BoggleMethods[] = {
  {"generate_board", boggle_generateAndLoadBoard,\
    METH_VARARGS, \
    "Generate and Return boggle board\n"
     "arg1 = List (empty)\n"
     "arg2 = int (length)\n"
     "arg3 = int (width)"},
  {"add_word" , boggle_addWordToDictionary, \
    METH_VARARGS, \
    "Add word to the dictionary (Could be Deprecated)\n"
    "arg1 = List (words)"},
  {"check_word", boggle_wordExistsInDictionary, \
    METH_VARARGS, \
      "check a word if it is in dictionary (Could be Deprecated)\n"
      "arg1 = String" },
  {"check_answers", boggle_checkAnswers, \
    METH_VARARGS, \
      "check a list if it is in dictionary as well as board\n"
      "arg1 = list of strings" },
  {NULL,NULL, 0 , NULL}
};

PyMODINIT_FUNC
initboggle(void)
{
  FALSE = Py_BuildValue("b", 0);
  TRUE = Py_BuildValue("b", 1);
  PyObject *m;
  m = Py_InitModule("boggle", BoggleMethods);
  if(m == NULL)
    return;
}

static PyObject* 
boggle_checkAnswers(PyObject* self, PyObject* args) {
  PyObject* listObj;
  PyObject* answersObj = PyList_New(0);

  if(!PyArg_ParseTuple(args, "O!", &PyList_Type, &listObj)) return FALSE;

  int numWords =0;
  numWords = PyList_Size(listObj);

  if(numWords < 0) return FALSE;

  std::string* words = new std::string[numWords];
  int* answers = new int[numWords];

  for(int i=0 ; i < numWords; i++ ) {
    PyObject* temp = PyList_GetItem(listObj, i);
    char* strptr = PyString_AsString(temp);
    words[i].assign(strptr);
  }

  game.checkAnswers(words, numWords, &answers[0]);

  for(int i=0; i < numWords; i++) {
    if(PyList_Append(answersObj, Py_BuildValue("i", answers[i]))) {
      return PyErr_SetFromErrno(PyErr_Occurred());
    }
  }

  return answersObj;
}

static PyObject*
boggle_wordExistsInDictionary(PyObject* self, PyObject* args)
{

  const char* word_ptr;
  int length;

  if(!PyArg_ParseTuple(args, "s#", &word_ptr, &length)) return FALSE;


  std::string word(word_ptr);

  if(!game.wordExistsInDict(word)) 
    return FALSE;

  return TRUE;
}

static PyObject*
boggle_addWordToDictionary(PyObject* self, PyObject* args)
{
  PyObject* listObj;

  if(!PyArg_ParseTuple(args, "O!", &PyList_Type, &listObj)) return FALSE;

  int numLines =0;
  numLines = PyList_Size(listObj);

  if(numLines < 0) return FALSE;

  std::string word;

  for(int i=0 ; i < numLines; i++ ) {
    PyObject* temp = PyList_GetItem(listObj, i);
    char* strptr = PyString_AsString(temp);
    word.assign(strptr);
    if(!game.addWordToDict(word)) 
      return PyErr_SetFromErrno(PyErr_Occurred());
  }

  unsigned int tsize = game.dictionary_size();
  return Py_BuildValue("i", tsize);
}

static PyObject*
boggle_generateAndLoadBoard(PyObject* self, PyObject* args)
{
  PyObject* listObj;
  int length;
  int width;
  char* board;
  if(!PyArg_ParseTuple(args, "O!ii", &PyList_Type, &listObj, &length,\
        &width)) return FALSE;

  int numLines =0;
  numLines = PyList_Size(listObj);

  if(numLines < 0) return FALSE;

  if(length == 0 || width == 0)  return FALSE;

  // fill python list with returned board
  int total = length*width;
  board = (char*) malloc(total);
  memset(board, 0, total);

  // raise an exception
  if(!board)
      return PyErr_NoMemory();

  if(!game.generateAndLoadBoard(board, length, width)) 
      return PyErr_SetFromErrno(PyErr_Occurred());
  
  // fill up the list
  while(total) {
    int index = total - 1;
    if(PyList_Append(listObj, Py_BuildValue("c",board[index]))) {
      return PyErr_SetFromErrno(PyErr_Occurred());
    }
    total--;
  }

  free(board);

  return TRUE;
}
